﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Chapter05
{
    using System.IO;
    using System.Collections;
    using System.Runtime.CompilerServices;

    partial class Program
    {
        internal static void Begin(Action action, bool active = false)
        {
            if (active)
            {
                Console.WriteLine("开始演示：");
                action();
                Console.WriteLine("演示完毕：");
                Console.ReadLine();
            }
        }

        internal static void C01()
        {
            {
                int a = 0;
                System.Int32 b = 0;
                int c = new int();
                System.Int32 d = new System.Int32();
                Console.WriteLine("{0} {1} {2} {3}", a, b, c, d);
            }
            BinaryReader br = new BinaryReader(new FileStream(null, FileMode.Open));
            {
                float val = br.ReadSingle();
            }
            {
                Single val = br.ReadSingle();
            }
            br.Close();
            {
                Int32 i = 5;
                Int64 l = i;
            }
            {
                Int32 i = 5;
                Int64 l = i;
                Single s = i;
                byte b = (byte)i;
                Int16 v = (Int16)s;
            }
            {
                Console.WriteLine(123.ToString() + 456.ToString());
                Boolean found = false;
                Int32 x = 100 + 20 + 3;
                string s = "a " + "bc";
                Console.WriteLine("{0} {1} {2}", found, x, s);
            }
            {
                Int32 x = 100;
                Int32 y = x + 23;
                Boolean lessThanFifty = (y < 50);
            }
            {
                Byte b = 100;
                b = (byte)(b + 200);
            }
            {
                UInt32 invalid = unchecked((UInt32)(-1));
                Console.WriteLine(invalid);
            }
            {
                try
                {
                    byte b = 100;
                    b = checked((byte)(b + 200));
                }
                catch (Exception e)
                {
                    Console.WriteLine(e.Message);
                }
            }
            {
                byte b = 100;
                b = (byte)checked(b + 200);
            }
            {
                checked
                {
                    byte b = 100;
                    b = (byte)(b + 200);
                }
                checked
                {
                    byte b = 100;
                    b += 200;
                }
            }
        }

        internal static void C02()
        {
            ValueTypeDemo();
            {
                SomeVal v1 = new SomeVal();
                Int32 a = v1.x;
            }
            {
                SomeVal v1;
                Int32 a = v1.x = 0;
            }
        }

        private class SomeRef { internal Int32 x;}

        private struct SomeVal { internal Int32 x;}

        private static void ValueTypeDemo()
        {
            SomeRef r1 = new SomeRef();
            SomeVal v1 = new SomeVal();
            r1.x = 5;
            v1.x = 5;
            Console.WriteLine(r1.x);
            Console.WriteLine(v1.x);
            SomeRef r2 = r1;
            SomeVal v2 = v1;
            r1.x = 8;
            v1.x = 9;
            Console.WriteLine(r1.x);
            Console.WriteLine(r2.x);
            Console.WriteLine(v1.x);
            Console.WriteLine(v2.x);
        }

        internal static void C03()
        {
            {
                ArrayList a = new ArrayList();
                Point p;
                for (int i = 0; i < 10; i++)
                {
                    p.x = p.y = 1;
                    a.Add(p);
                }
            }
            {
                try
                {
                    int x = 5;
                    object o = x;
                    Int16 y = (Int16)o;
                }
                catch (Exception e)
                {
                    Console.WriteLine(e.Message);
                }
            }
            {
                int x = 5;
                object o = x;
                Int16 y = (Int16)(Int32)o;
            }
            {
                Point p;
                p.x = p.y = 1;
                object o = p;
                p = (Point)o;
            }
            {
                Point p;
                p.x = p.y = 1;
                object o = p;
                p = (Point)o;
                p.x = 2;
                o = p;
            }
            {
                Int32 v = 5;
                object o = v;
                v = 123;
                Console.WriteLine(v + ", " + (Int32)o);
            }
            {
                Int32 v = 5;
                object o = v;
                v = 123;
                Console.WriteLine(v);
                v = (Int32)o;
                Console.WriteLine(v);
            }
            {
                Int32 v = 5;
#if INEFFICIENT
                Console.WriteLine("{0}, {1}, {2}", v, v, v);
#else
                object o = v;
                Console.WriteLine("{0}, {1}, {2}", o, o, o);
#endif
            }
            {
                Point p1 = new Point(10, 10);
                Point p2 = new Point(20, 20);
                Console.WriteLine(p1.ToString());
                Console.WriteLine(p1.GetType());
                Console.WriteLine(p1.CompareTo(p2));
                IComparable c = p1;
                Console.WriteLine((c.GetType()));
                Console.WriteLine(p1.CompareTo(c));
                Console.WriteLine(c.CompareTo(p2));
                p2 = (Point)c;
                Console.WriteLine(p2.ToString());
            }
            {
                Point p = new Point(1, 1);
                Console.WriteLine(p);
                p.Change(2, 2);
                Console.WriteLine(p);
                object o = p;
                Console.WriteLine(o);
                ((Point)o).Change(3, 3);
                Console.WriteLine(o);
            }
            {
                Point p = new Point(1, 1);
                Console.WriteLine(p);
                p.Change(2, 2);
                Console.WriteLine(p);
                object o = p;
                Console.WriteLine(o);
                ((Point)o).Change(3, 3);
                Console.WriteLine(o);
                ((IChangeBoxedPoint)o).Change(4, 4);
                Console.WriteLine(p);
                ((IChangeBoxedPoint)o).Change(5, 5);
                Console.WriteLine(o);
            }
        }

        private struct Point : IComparable, IChangeBoxedPoint
        {
            internal Int32 x;
            internal Int32 y;

            internal Point(Int32 x, Int32 y)
            {
                this.x = x;
                this.y = y;
            }

            internal int CompareTo(Point other)
            {
                return Math.Sign(Math.Sqrt(x * x + y * y) - Math.Sqrt(other.x * other.x + other.y * other.y));
            }

            public int CompareTo(object obj)
            {
                if (GetType() != obj.GetType())
                {
                    throw new ArgumentException("o is not a Point");
                }
                return CompareTo((Point)obj);
            }

            public override string ToString()
            {
                return string.Format("{0}, {1}", x, y);
            }

            public void Change(int x, int y)
            {
                this.x = x;
                this.y = y;
            }

            public override int GetHashCode()
            {
                return x ^ y;
            }
        }

        private interface IChangeBoxedPoint
        {
            void Change(int x, int y);
        }

        internal static void C04()
        {
            Console.WriteLine((new Point(2, 2)).GetHashCode());
            Console.WriteLine((new Point(1, 1)).GetHashCode());
        }

        internal static void C05()
        {
            for (int i = 0; i < 2; i++)
            {
                dynamic arg = (i == 0) ? (dynamic)5 : (dynamic)"A";
                dynamic result = Plus(arg);
                M(result);
            }
        }

        private static dynamic Plus(dynamic arg)
        {
            return arg += arg;
        }

        private static void M(int n)
        {
            Console.WriteLine("M(int): " + n);
        }

        private static void M(string s)
        {
            Console.WriteLine("M(string): " + s);
        }
    }
}
